package tcc.ejb.autenticador.controle;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import tcc.ejb.autenticador.controle.exceptions.IllegalOrphanException;
import tcc.ejb.autenticador.controle.exceptions.NonexistentEntityException;
import tcc.ejb.autenticador.controle.exceptions.PreexistingEntityException;
import tcc.ejb.autenticador.entidade.Aplicacao;
import tcc.ejb.autenticador.entidade.Profissional;
import tcc.ejb.autenticador.entidade.Unidade;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author Maciel
 */
public class ProfissionalJpaController {

	private List<Profissional> listaProfissional;

	public ProfissionalJpaController() {
		emf = Persistence.createEntityManagerFactory("autenticador");
	}
	private EntityManagerFactory emf = null;

	public EntityManager getEntityManager() {
		return emf.createEntityManager();
	}

	public void create(Profissional profissional) throws PreexistingEntityException, Exception {
		if (profissional.getAplicacaoList() == null) {
			profissional.setAplicacaoList(new ArrayList<Aplicacao>());
		}
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			Unidade unidade = profissional.getUnidade();
			if (unidade != null) {
				unidade = em.getReference(unidade.getClass(), unidade.getId());
				profissional.setUnidade(unidade);
			}
			List<Aplicacao> attachedAplicacaoList = new ArrayList<Aplicacao>();
			for (Aplicacao aplicacaoListAplicacaoToAttach : profissional.getAplicacaoList()) {
				aplicacaoListAplicacaoToAttach = em.getReference(aplicacaoListAplicacaoToAttach.getClass(), aplicacaoListAplicacaoToAttach.getId());
				attachedAplicacaoList.add(aplicacaoListAplicacaoToAttach);
			}
			profissional.setAplicacaoList(attachedAplicacaoList);
			em.persist(profissional);
			if (unidade != null) {
				unidade.getProfissionalList().add(profissional);
				unidade = em.merge(unidade);
			}
			for (Aplicacao aplicacaoListAplicacao : profissional.getAplicacaoList()) {
				Profissional oldProfissionalOfAplicacaoListAplicacao = aplicacaoListAplicacao.getProfissional();
				aplicacaoListAplicacao.setProfissional(profissional);
				aplicacaoListAplicacao = em.merge(aplicacaoListAplicacao);
				if (oldProfissionalOfAplicacaoListAplicacao != null) {
					oldProfissionalOfAplicacaoListAplicacao.getAplicacaoList().remove(aplicacaoListAplicacao);
					oldProfissionalOfAplicacaoListAplicacao = em.merge(oldProfissionalOfAplicacaoListAplicacao);
				}
			}
			em.getTransaction().commit();
		} catch (Exception ex) {
			if (findProfissional(profissional.getId()) != null) {
				throw new PreexistingEntityException("Profissional " + profissional + " already exists.", ex);
			}
			throw ex;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public void edit(Profissional profissional) throws IllegalOrphanException, NonexistentEntityException, Exception {
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			Profissional persistentProfissional = em.find(Profissional.class, profissional.getId());
			Unidade unidadeOld = persistentProfissional.getUnidade();
			Unidade unidadeNew = profissional.getUnidade();
			List<Aplicacao> aplicacaoListOld = persistentProfissional.getAplicacaoList();
			List<Aplicacao> aplicacaoListNew = profissional.getAplicacaoList();
			List<String> illegalOrphanMessages = null;
			for (Aplicacao aplicacaoListOldAplicacao : aplicacaoListOld) {
				if (!aplicacaoListNew.contains(aplicacaoListOldAplicacao)) {
					if (illegalOrphanMessages == null) {
						illegalOrphanMessages = new ArrayList<String>();
					}
					illegalOrphanMessages.add("You must retain Aplicacao " + aplicacaoListOldAplicacao + " since its profissional field is not nullable.");
				}
			}
			if (illegalOrphanMessages != null) {
				throw new IllegalOrphanException(illegalOrphanMessages);
			}
			if (unidadeNew != null) {
				unidadeNew = em.getReference(unidadeNew.getClass(), unidadeNew.getId());
				profissional.setUnidade(unidadeNew);
			}
			List<Aplicacao> attachedAplicacaoListNew = new ArrayList<Aplicacao>();
			for (Aplicacao aplicacaoListNewAplicacaoToAttach : aplicacaoListNew) {
				aplicacaoListNewAplicacaoToAttach = em.getReference(aplicacaoListNewAplicacaoToAttach.getClass(), aplicacaoListNewAplicacaoToAttach.getId());
				attachedAplicacaoListNew.add(aplicacaoListNewAplicacaoToAttach);
			}
			aplicacaoListNew = attachedAplicacaoListNew;
			profissional.setAplicacaoList(aplicacaoListNew);
			profissional = em.merge(profissional);
			if (unidadeOld != null && !unidadeOld.equals(unidadeNew)) {
				unidadeOld.getProfissionalList().remove(profissional);
				unidadeOld = em.merge(unidadeOld);
			}
			if (unidadeNew != null && !unidadeNew.equals(unidadeOld)) {
				unidadeNew.getProfissionalList().add(profissional);
				unidadeNew = em.merge(unidadeNew);
			}
			for (Aplicacao aplicacaoListNewAplicacao : aplicacaoListNew) {
				if (!aplicacaoListOld.contains(aplicacaoListNewAplicacao)) {
					Profissional oldProfissionalOfAplicacaoListNewAplicacao = aplicacaoListNewAplicacao.getProfissional();
					aplicacaoListNewAplicacao.setProfissional(profissional);
					aplicacaoListNewAplicacao = em.merge(aplicacaoListNewAplicacao);
					if (oldProfissionalOfAplicacaoListNewAplicacao != null && !oldProfissionalOfAplicacaoListNewAplicacao.equals(profissional)) {
						oldProfissionalOfAplicacaoListNewAplicacao.getAplicacaoList().remove(aplicacaoListNewAplicacao);
						oldProfissionalOfAplicacaoListNewAplicacao = em.merge(oldProfissionalOfAplicacaoListNewAplicacao);
					}
				}
			}
			em.getTransaction().commit();
		} catch (Exception ex) {
			String msg = ex.getLocalizedMessage();
			if (msg == null || msg.length() == 0) {
				Integer id = profissional.getId();
				if (findProfissional(id) == null) {
					throw new NonexistentEntityException("The profissional with id " + id + " no longer exists.");
				}
			}
			throw ex;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public void destroy(Integer id) throws IllegalOrphanException, NonexistentEntityException {
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			Profissional profissional;
			try {
				profissional = em.getReference(Profissional.class, id);
				profissional.getId();
			} catch (EntityNotFoundException enfe) {
				throw new NonexistentEntityException("The profissional with id " + id + " no longer exists.", enfe);
			}
			List<String> illegalOrphanMessages = null;
			List<Aplicacao> aplicacaoListOrphanCheck = profissional.getAplicacaoList();
			for (Aplicacao aplicacaoListOrphanCheckAplicacao : aplicacaoListOrphanCheck) {
				if (illegalOrphanMessages == null) {
					illegalOrphanMessages = new ArrayList<String>();
				}
				illegalOrphanMessages.add("This Profissional (" + profissional + ") cannot be destroyed since the Aplicacao " + aplicacaoListOrphanCheckAplicacao + " in its aplicacaoList field has a non-nullable profissional field.");
			}
			if (illegalOrphanMessages != null) {
				throw new IllegalOrphanException(illegalOrphanMessages);
			}
			Unidade unidade = profissional.getUnidade();
			if (unidade != null) {
				unidade.getProfissionalList().remove(profissional);
				unidade = em.merge(unidade);
			}
			em.remove(profissional);
			em.getTransaction().commit();
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public List<Profissional> findProfissionalEntities() {
		return findProfissionalEntities(true, -1, -1);
	}

	public List<Profissional> findProfissionalEntities(int maxResults, int firstResult) {
		return findProfissionalEntities(false, maxResults, firstResult);
	}

	private List<Profissional> findProfissionalEntities(boolean all, int maxResults, int firstResult) {
		EntityManager em = getEntityManager();
		try {
			CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
			cq.select(cq.from(Profissional.class));
			Query q = em.createQuery(cq);
			if (!all) {
				q.setMaxResults(maxResults);
				q.setFirstResult(firstResult);
			}
			return q.getResultList();
		} finally {
			em.close();
		}
	}

	public Profissional findProfissional(Integer id) {
		EntityManager em = getEntityManager();
		try {
			return em.find(Profissional.class, id);
		} finally {
			em.close();
		}
	}


	public List<Profissional> findProfissionalEntities(Map<String,String> filters,boolean like){
		EntityManager em = getEntityManager();
		try {    
			String stringQuery = "SELECT p FROM Profissional p where ";


			Set s=filters.entrySet();
			Iterator it = s.iterator();
			while (it.hasNext()) {
				Map.Entry valores = (Map.Entry)it.next();
				if(like){
					stringQuery += " UPPER(p."+valores.getKey() + ") like " + ":"+valores.getKey()+" AND ";
				}else{
					stringQuery += " p."+valores.getKey() + " = " + ":"+valores.getKey()+" AND ";
				}
			}				

			stringQuery += " p.id>0";

			Query q = em.createQuery (stringQuery);

			Set s2=filters.entrySet();
			Iterator it2 = s2.iterator();
			while (it2.hasNext()) {
				Map.Entry valores = (Map.Entry)it2.next();
				if(like){
					StringBuilder sb = new StringBuilder();
					sb.append("%");
					sb.append(valores.getValue().toString().toUpperCase());
					sb.append("%");
					q.setParameter(valores.getKey().toString() , sb);
				}else{
					q.setParameter(valores.getKey().toString() , valores.getValue().toString());
				}
			}		
			List<Profissional> listProfissional = q.getResultList();

			return listProfissional;

		}catch (Exception e) {
			return null;
		}finally {
			em.close();
		}		
	}



	//esse cara aqui -----------------------------------
	public List<Profissional> findProfissionalEntities(int maxResults, int firstResult, String sortField, boolean sortOrder, Map<String, String> filters, boolean like) {
		EntityManager em = getEntityManager();
		try {    
			String stringQuery = "select p from Profissional p where ";
			Set s=filters.entrySet();
			Iterator it = s.iterator();
			while (it.hasNext()) {
				Map.Entry valores = (Map.Entry)it.next();
				if(like){
					stringQuery += " upper(p."+valores.getKey() + ") like " + ":"+valores.getKey().toString().replace(".", "")+" AND ";
				}else{
					stringQuery += " p."+valores.getKey() + " = " + ":"+valores.getKey().toString().replace(".", "")+" AND ";
				}
			}				

			stringQuery += " p.id>0 ORDER BY p.nome";

			Query q = em.createQuery (stringQuery);

			s=filters.entrySet();
			it = s.iterator();
			String valorTemp;
			while (it.hasNext()) {
				Map.Entry valores = (Map.Entry)it.next();
				if(like==true){
					valorTemp = valores.getValue().toString().toUpperCase();
					q.setParameter(valores.getKey().toString().replace(".", "") , "%"+valorTemp+"%");
				}else{
					q.setParameter(valores.getKey().toString().replace(".", "") , valores.getValue().toString());
				}
			}		
			q.setMaxResults(maxResults);
			q.setFirstResult(firstResult);     	

			List<Profissional> listProfissional = q.getResultList();

			return listProfissional;


		}catch (Exception e) {
			return null;
		}finally {
			em.close();
		}		
	}    
	//----------------------------------------------------


	public int countProfissionalEntities(Map<String, String> filters, boolean like) {
		EntityManager em = getEntityManager();
		try {    
			String stringQuery = "select count(p) from Profissional p where ";
			Set s=filters.entrySet();
			Iterator it = s.iterator();
			while (it.hasNext()) {
				Map.Entry valores = (Map.Entry)it.next();
				if(like){
					stringQuery += " upper(p."+valores.getKey() + ") like " + ":"+valores.getKey().toString().replace(".", "")+" AND ";
				}else{
					stringQuery += " p."+valores.getKey() + " = " + ":"+valores.getKey().toString().replace(".", "")+" AND ";
				}
			}				

			stringQuery += " p.id>0";

			Query q = em.createQuery (stringQuery);

			s=filters.entrySet();
			it = s.iterator();
			String valorTemp;
			while (it.hasNext()) {
				Map.Entry valores = (Map.Entry)it.next();
				if(like==true){
					valorTemp = valores.getValue().toString().toUpperCase();
					q.setParameter(valores.getKey().toString().replace(".", "") , "%"+valorTemp+"%");
				}else{
					q.setParameter(valores.getKey().toString().replace(".", "") , valores.getValue().toString());
				}
			}		
			return ((Long) q.getSingleResult()).intValue();


		}catch (Exception e) {
			return 0;
		}finally {
			em.close();
		}	

	}		
	public int getProfissionalCount() {
		EntityManager em = getEntityManager();
		try{
			String stringQuery = "select count(p) from Profissional p";
			Query q = em.createQuery (stringQuery);
			int resultado = ((Long) q.getSingleResult()).intValue();
			return resultado;
		}catch (Exception e) {
			    e.printStackTrace();
				return 0;
		}finally{
			em.close();
		}
		

	}
}
